package org.zpmis.domain.sequence.service.impl;

import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zpmis.common.constant.UserConstants;
import org.zpmis.common.enums.SequenceEnum;
import org.zpmis.common.exception.BusinessException;
import org.zpmis.common.result.ResultCode;
import org.zpmis.common.service.AbstractService;
import org.zpmis.common.utils.RedisUtil;
import org.zpmis.domain.dict.enums.SysDictEnum;
import org.zpmis.domain.dict.model.SysDict;
import org.zpmis.domain.dict.service.SysDictService;
import org.zpmis.domain.sequence.dao.SequenceMapper;
import org.zpmis.domain.sequence.model.Sequence;
import org.zpmis.domain.sequence.service.SequenceService;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;


/**
 * Created with CodeGenerator
 * Description:
 * @author  Yang
 * Date: 2021-7-20
 * Time: 17:10:16
 */
@Service
@Transactional
public class SequenceServiceImpl extends AbstractService<Sequence> implements SequenceService {

    @Resource
    private SequenceMapper sequenceMapper;

    @Reference
    private SysDictService sysDictService;

    @Resource
    private RedisUtil redisUtil;

    private static String SEQUENCE_FORMAT="sequence_format_%s";

    private static String SEQUENCE_PREFIX="sequence_prefix_%s";

    private static String SEQUENCE_RULE="sequence_rule";

    private static int REDIS_LOCK_TIMOUT=40000;

    /**
     * 获取不同类型下的系统编号
     * @param sequenceEnum
     * @return
     * @throws BusinessException
     */
    @Override
    public String getSequenceNum(SequenceEnum sequenceEnum) throws BusinessException{
        //判断清零规则
        Map<String,Object> param = new HashMap<>();
        param.put("name", SEQUENCE_RULE);
        param.put("isDeleted", false);
        param.put("businessType", SysDictEnum.SYSTEM_ADMIN.code());
        SysDict sysDict = sysDictService.findByModel(param);
        //查询当前日期的序列Key
        String sequenceKey = String.valueOf(LocalDate.now().getYear());
        if(sysDict != null){
            if(sysDict.getValue().equals(SequenceEnum.YEAR_KEY.code())){
                sequenceKey= String.valueOf(LocalDate.now().getYear());
            }else if(sysDict.getValue().equals(SequenceEnum.MONTH_KEY.code())){
                sequenceKey= LocalDate.now().getYear()+"-"+LocalDate.now().getMonthValue();
            }
        }
        //获取项目编号补零规则
        Map<String,Object> formatParam = new HashMap<>();
        formatParam.put("name", String.format(SEQUENCE_FORMAT,sequenceEnum.code()));
        formatParam.put("isDeleted", false);
        formatParam.put("businessType", SysDictEnum.SYSTEM_ADMIN.code());
        SysDict formatDict = sysDictService.findByModel(formatParam);
        String format = "%04d";
        if(formatDict != null){
            format = formatDict.getValue();
        }
        //获取项目编号前缀
        Map<String,Object> prefixParam = new HashMap<>();
        prefixParam.put("name", String.format(SEQUENCE_PREFIX,sequenceEnum.code()));
        prefixParam.put("isDeleted", false);
        prefixParam.put("businessType", SysDictEnum.SYSTEM_ADMIN.code());
        SysDict prefixDict = sysDictService.findByModel(prefixParam);
        String prefix = "ZZ" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        if(prefixDict != null){
            prefix = prefixDict.getValue() + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        }
        //设置分布式锁 防止编号重复获取
        if(!redisUtil.lock(String.format(UserConstants.SEQUENCE_LOCK_PREFIX,sequenceEnum.code(),sequenceKey), REDIS_LOCK_TIMOUT)){
            throw new BusinessException(ResultCode.SYS_NUMBER_ERROR);
        }
        try {
            //判断获取哪种类型的序列
            Sequence sequence = sequenceMapper.selectOne(Sequence.builder().sequenceType(sequenceEnum.code()).sequenceKey(sequenceKey).build());
            if (sequence == null) {
                    int insert = sequenceMapper.insert(
                            Sequence.builder()
                                    .sequenceId(1)
                                    .sequenceType(sequenceEnum.code())
                                    .sequenceKey(sequenceKey)
                                    .createTime(Instant.now().toEpochMilli())
                                    .build()
                    );
                    if (insert == 1) {
                        return prefix+String.format(format, 1);
                    }
                }
            sequence.setSequenceId(sequence.getSequenceId() + 1);
            sequence.setUpdateTime(Instant.now().toEpochMilli());
            //获取之后更新数据库中的序列值+1
            sequenceMapper.updateByPrimaryKeySelective(sequence);
            return prefix+String.format(format,sequence.getSequenceId());
        } catch (Exception e) {
            throw new BusinessException(ResultCode.SYS_NUMBER_ERROR);
        } finally {
            redisUtil.unLock(String.format(UserConstants.SEQUENCE_LOCK_PREFIX,sequenceEnum.code(),sequenceKey));
        }
    }
}
